Skip to content

1. BMP280大气气压传感器模块实物图及原理图

!!!注意看这个下面这幅BMP280原理图,SDO引脚是否接地(连接GND),其次,看CSB引脚是否固定了高电平(硬链连接上拉电阻)

image1

image2

image3

image4

2. 四引脚的BMP280的I2C协议有什么特点?

2.1 4 Pin BMP280 仅支持I2C

具体看BMP280数据手册,现在这款BMP280大气气压传感器模块已经被厂家固定为4个引脚了,分别为VIN、GND、SCL、SDA。

1. 由原理图可以看出BMP280的SDO引脚连接的是GND 接地,所以我们的这块板子的I2C 7位地址为0x76,也就是7位地址为1110110 (0x76)。

2. 原理图中CSB通过上拉电阻,固定为了高电平,所以无法使用SPI通信协议。

如果无法预览,请点击 此处下载 BMP280数据手册 PDF 文件

BMP280数据手册里写明:

Page28:5.2 I²C Interface

The 7-bit device address is 111011x. The 6 MSB bits are fixed. The last bit is changeable by SDO value and can be changed during operation. Connecting SDO to GND results in slave address 1110110 (0x76); connection it to VDDIO results in slave address 1110111 (0x77), which is the same as BMP180’s I²C address. The SDO pin cannot be left floating; if left floating, the I²C address will be undefined. The I²C interface uses the following pins:

  • SCK: serial clock (SCL)
  • SDI: data (SDA)
  • SDO: Slave address LSB (GND = ‘0’, VDDIO = ‘1’) CSB must be connected to VDDIO to select I²C interface. SDI is bi-directional with open drain to GND: it must be externally connected to VDDIO via a pull up resistor. Refer to chapter 6 for connection instructions.

Page30:5.3 SPI interface

The SPI interface is compatible with SPI mode ‘00’ (CPOL = CPHA = ‘0’) and mode ‘11’ (CPOL = CPHA = ‘1’). The automatic selection between mode ‘00’ and ‘11’ is determined by the value of SCK after the CSB falling edge.

2.2 BMP280支持三种电源模式

Page15: 3.6 Power modes The BMP280 offers three power modes: sleep mode, forced mode and normal mode. These can be selected using the mode[1:0] bits in control register 0xF4. Table 10: mode settings BELOW

mode[1:0]
(CMD)
Mode
00sleep mode
01 and 10Forced mode (SoverEng used this)
11Normal mode

3. BMP280 数据手册摘要有哪些要了解的?

3.1 BMP280数据手册基本信息

  • 传感器型号:BMP280
  • 制造商:Bosch Sensortec
  • 文档版本:1.14
  • 发布日期:2015年5月5日
  • 文档编号:BST-BMP280-DS001-11

3.2 BMP280的产品概述

BMP280是一款基于Piezo-resistive技术的数字气压传感器,专为移动应用设计,具有高精度、低功耗和小尺寸特性。作为BMP180的继任者,其在噪声水平、接口支持和封装尺寸上均有显著提升,适合电池供电设备如手机、GPS模块和手表等场景。

3.3 关键参数

参数规格
压力范围300~1100 hPa(等效海拔+9000~-500米)2页
封装8引脚LGA金属盖,尺寸2.0×2.5 mm²,高度0.95 mm2页
精度- 相对精度:±0.12 hPa(等效±1米,950~1050 hPa @25°C)
- 绝对精度:典型±1 hPa(950~1100 hPa,0~+40°C)2页 2页
温度系数偏移1.5 Pa/K(等效12.6 cm/K,25~40°C @900 hPa)2页
接口I²C(最高3.4 MHz)、SPI(3/4线,最高10 MHz)2页 2页
功耗2.7 µA @1 Hz采样率2页
工作温度范围-40~+85°C2页
环保特性RoHS合规、无卤素、MSL 12页 2页

3.4 与BMP180对比

参数BMP180BMP280
封装尺寸3.6×3.8 mm²2.0×2.5 mm²(缩小63%)
最小供电电压(VDD)1.80 V1.71 V
功耗(@3 Pa噪声)12 µA2.7 µA
噪声3 Pa1.3 Pa
接口仅I²CI²C + SPI(3/4线)
测量模式仅强制模式强制/正常模式
滤波器5种带宽选项

3.5 典型应用与目标设备

3.5.1 典型应用

  • GPS导航增强(首次定位时间优化、航位推算、坡度检测)2页
  • 室内导航(楼层检测、电梯检测)2页
  • 户外导航、休闲运动设备2页
  • 气象预测2页
  • 医疗健康(如肺活量计)2页
  • 垂直速度指示(上升/下降速度)2页

3.5.2 目标设备

手机、平板电脑、GPS设备、导航系统、便携式医疗设备、家用气象站、飞行玩具、手表等2页~2页

3.6 功能描述

3.6.1 工作模式

  • 睡眠模式:默认模式,无测量,功耗最低16页
  • 强制模式:单次测量后返回睡眠模式,适合低采样率场景16页(本节都是此模式)
  • 正常模式:循环进行测量与待机,支持IIR滤波,适合需持续监测场景16页

3.6.2 过采样与滤波

  • 过采样设置:压力(×1~×16)和温度(×1~×16)可独立配置,平衡精度与功耗10页
  • IIR滤波器:5种系数(2/4/8/16),抑制短期压力波动(如关门噪声)10页

3.6.3 数据读取与补偿

  • 数据输出:20位无符号压力/温度原始数据,需通过校准参数补偿19页
  • 校准参数:存储于0x88~0xA1寄存器,包括温度(dig_T1~T3)和压力(dig_P1~P9)补偿系数21页
  • 补偿公式:提供64位整数、32位整数和浮点实现,确保高精度转换21页 44页

3.7 BMP280 接口规范

3.7.1 支持 I²C接口

  • 7位地址:0x76(SDO接地)或0x77(SDO接VDDIO)28页
  • 支持标准/快速/高速模式,SDA/SCL需外部上拉电阻28页

3.7.2 SPI接口

  • 支持4线(SDI/SDO/SCK/CSB)和3线(SDI复用)模式,SPI模式00/1130页
  • 最高时钟频率10 MHz,CSB低电平激活34页

4. BMP280的AI 提示词有哪些要明确的

现在我手头上有一块 BMP280 大气压传感器模块,它有 4 个引脚,分别是 VIN、GND、SCL 和 SDA。 我已经将这个 BMP280 传感器模块的引脚连接到了 ESP32-S3 开发板上,具体接线如下:

  1. SCL 引脚连接到 ESP32-S3 的 7 号引脚
  2. SDA 引脚连接到了 15 号引脚
    我电脑目前使用的是 VS Code 加 ESP-IDF 插件进行编程,已经通过安装管理器安装好了 ESP-IDF V6.0 版本。
    现在请你告诉我应该怎么写代码。要求如下:
  3. 不要使用现成的 BMP280 库或组件
  4. 我需要从头开始写,用 I2C 驱动来写
  5. 我看了原理图以及BMP280 datasheet 数据手册,SDO接GND,CSB硬连接了上拉电阻, BMP280 只有 4 个引脚,所以它的 I2C 地址就是 0x76,你看一下是否正确
    请直接给出代码。

5. I2C协议读取BMP280大气气压传感器数据完整流程

流程

6. ESP32 s3 编写驱动读取BMP280 气压数据(ESP-IDF)

C
#include <stdio.h>
#include <math.h>
#include "freertos/FreeRTOS.h"   // FreeRTOS 实时操作系统头文件
#include "freertos/task.h"        // FreeRTOS 任务管理(如 vTaskDelay 延时)
#include "driver/i2c_master.h"    // ESP-IDF 的 I2C 主机驱动
#include "esp_log.h"              // ESP-IDF 日志打印工具

static const char *TAG = "BMP280"; // 日志标签,打印时会显示 [BMP280]

/* =============================================
   I2C 引脚与通信参数定义
   BMP280 通过 I2C 总线与 ESP32 通信
   ============================================= */
#define I2C_MASTER_SCL_IO          GPIO_NUM_7    // SCL(时钟线)连接的 GPIO 引脚
#define I2C_MASTER_SDA_IO          GPIO_NUM_15   // SDA(数据线)连接的 GPIO 引脚
#define I2C_MASTER_FREQ_HZ         400000        // I2C 通信速率:400kHz(快速模式)
#define I2C_PORT                   I2C_NUM_0     // 使用 ESP32 的 I2C 控制器 0
#define BMP280_SENSOR_ADDR         0x76          // BMP280 的 I2C 地址(SDO 引脚接 GND 时为 0x76)
#define I2C_TIMEOUT_MS             1000          // I2C 通信超时时间:1000 毫秒

/* =============================================
   BMP280 寄存器地址定义
   寄存器是传感器内部的"存储格子",通过读写这些地址来控制传感器
   ============================================= */
#define BMP280_REG_CHIP_ID         0xD0  // 芯片 ID 寄存器,读出来应该是 0x58
#define BMP280_REG_RESET           0xE0  // 软复位寄存器,写入 0xB6 可重置传感器
#define BMP280_REG_STATUS          0xF3  // 状态寄存器,可查询传感器是否正在测量
#define BMP280_REG_CTRL_MEAS       0xF4  // 控制寄存器,设置采样精度和工作模式
#define BMP280_REG_CONFIG          0xF5  // 配置寄存器,设置滤波器和待机时间
#define BMP280_REG_PRESS_MSB       0xF7  // 气压数据起始寄存器(共 6 字节:气压3字节+温度3字节)
#define BMP280_REG_CALIB_START     0x88  // 校准参数起始寄存器(共 24 字节)

/* =============================================
   数据类型别名定义
   为了和 BMP280 手册中的命名保持一致
   ============================================= */
typedef int32_t  BMP280_S32_t;  // 有符号 32 位整数
typedef uint32_t BMP280_U32_t;  // 无符号 32 位整数
typedef int64_t  BMP280_S64_t;  // 有符号 64 位整数(气压补偿需要更大范围)

/* =============================================
   全局句柄变量
   句柄是 ESP-IDF 用来管理硬件资源的"引用"
   ============================================= */
static i2c_master_bus_handle_t bus_handle; // I2C 总线句柄(代表整条 I2C 总线)
static i2c_master_dev_handle_t dev_handle; // I2C 设备句柄(代表总线上的 BMP280 这个设备)

/* =============================================
   校准参数(出厂时烧录在传感器内部)
   BMP280 的原始 ADC 数据不是真实的温度/气压值,
   需要用这些校准参数进行数学补偿计算才能得到真实值
   ============================================= */
static uint16_t dig_T1;                    // 温度校准参数 1(无符号)
static int16_t  dig_T2, dig_T3;           // 温度校准参数 2、3(有符号)
static uint16_t dig_P1;                    // 气压校准参数 1(无符号)
static int16_t  dig_P2, dig_P3, dig_P4, dig_P5; // 气压校准参数 2-5
static int16_t  dig_P6, dig_P7, dig_P8, dig_P9; // 气压校准参数 6-9
static BMP280_S32_t t_fine; // 温度补偿的中间值,气压补偿也需要用到它

/* =============================================
   底层 I2C 通信函数:写寄存器
   向传感器的某个寄存器写入一个字节的数据
   ============================================= */
static esp_err_t bmp280_write_reg(uint8_t reg_addr, uint8_t data) {
    // 把寄存器地址和数据打包成 2 字节,通过 I2C 发送给传感器
    uint8_t write_buf[2] = {reg_addr, data};
    return i2c_master_transmit(dev_handle, write_buf, sizeof(write_buf), I2C_TIMEOUT_MS);
}

/* =============================================
   底层 I2C 通信函数:读寄存器
   从传感器的某个寄存器开始,连续读取 len 个字节
   ============================================= */
static esp_err_t bmp280_read_reg(uint8_t reg_addr, uint8_t *data, size_t len) {
    // 先发送要读取的寄存器地址,再接收传感器返回的数据
    return i2c_master_transmit_receive(dev_handle, &reg_addr, 1, data, len, I2C_TIMEOUT_MS);
}

/* =============================================
   温度补偿算法(来自 BMP280 官方手册 3.11.3 节)
   
   传感器 ADC 读出的是原始数字值,不是摄氏度。
   这个函数用校准参数把原始值换算成真实温度。
   
   输入:adc_T —— 传感器读出的原始温度 ADC 值(20位)
   输出:返回温度值(单位:0.01°C,例如返回 2510 表示 25.10°C)
   副作用:同时计算并保存 t_fine(供气压补偿使用)
   ============================================= */
static BMP280_S32_t bmp280_compensate_T_int32(BMP280_S32_t adc_T) {
    BMP280_S32_t var1, var2, T;
    // 第一项:线性补偿
    var1 = ((((adc_T>>3) - ((BMP280_S32_t)dig_T1<<1))) * ((BMP280_S32_t)dig_T2)) >> 11;
    // 第二项:二次补偿(修正非线性误差)
    var2 = ( ((((adc_T>>4) - ((BMP280_S32_t)dig_T1)) * ((adc_T>>4) - ((BMP280_S32_t)dig_T1))) >> 12) * ((BMP280_S32_t)dig_T3) ) >> 14;
    // t_fine 是温度的精细中间值,后续气压补偿也需要它
    t_fine = var1 + var2;
    // 最终温度值(单位 0.01°C)
    T = (t_fine * 5 + 128) >> 8;
    return T;
}

/* =============================================
   气压补偿算法(来自 BMP280 官方手册 3.11.3 节)
   
   同样,ADC 读出的气压原始值需要用校准参数换算。
   注意:必须先调用温度补偿函数(更新 t_fine),再调用此函数!
   
   输入:adc_P —— 传感器读出的原始气压 ADC 值(20位)
   输出:返回气压值(单位:1/256 Pa,例如返回 25600000 表示 100000 Pa = 1000 hPa)
   ============================================= */
static BMP280_U32_t bmp280_compensate_P_int64(BMP280_S32_t adc_P) {
    BMP280_S64_t var1, var2, p;
    // 利用 t_fine 进行温度相关的气压修正
    var1 = ((BMP280_S64_t)t_fine) - 128000;
    var2 = var1 * var1 * (BMP280_S64_t)dig_P6;
    var2 = var2 + ((var1*(BMP280_S64_t)dig_P5)<<17);
    var2 = var2 + (((BMP280_S64_t)dig_P4)<<35);
    var1 = ((var1 * var1 * (BMP280_S64_t)dig_P3)>>8) + ((var1 * (BMP280_S64_t)dig_P2)<<12);
    var1 = (((((BMP280_S64_t)1)<<47)+var1))*((BMP280_S64_t)dig_P1)>>33;
    if (var1 == 0) return 0; // 防止除以零(避免程序崩溃)
    p = 1048576 - adc_P;
    p = (((p<<31) - var2) * 3125) / var1;
    var1 = (((BMP280_S64_t)dig_P9) * (p>>13) * (p>>13)) >> 25;
    var2 = (((BMP280_S64_t)dig_P8) * p) >> 19;
    // 最终气压值(单位:1/256 Pa)
    p = ((p + var1 + var2) >> 8) + (((BMP280_S64_t)dig_P7)<<4);
    return (BMP280_U32_t)p;
}

/* =============================================
   海拔换算函数(国际标准大气压模型)
   
   根据当前气压推算海拔高度。
   公式:h = 44330 × (1 - (P/P0)^0.1903)
   其中 P0 = 101325 Pa(海平面标准大气压)
   
   输入:pressure_pa —— 当前气压(单位:Pa)
   输出:返回估算海拔(单位:米)
   注意:这只是估算值,实际海拔受天气影响
   ============================================= */
static float pressure_to_altitude(float pressure_pa) {
    float sea_level_pa = 101325.0f; // 海平面标准大气压(Pa)
    return 44330.0f * (1.0f - powf((pressure_pa / sea_level_pa), 0.1903f));
}

/* =============================================
   单次测量函数(强制模式 Forced Mode)
   
   BMP280 有三种工作模式:
   - Sleep 模式:不测量,最省电
   - Forced 模式:触发一次测量,完成后自动回到 Sleep
   - Normal 模式:持续周期性测量
   
   这里使用 Forced 模式:每次需要数据时手动触发一次测量。
   
   输出参数:
     temperature —— 温度(°C)
     pressure    —— 气压(Pa)
     altitude    —— 估算海拔(m)
   ============================================= */
static esp_err_t bmp280_force_measurement(float *temperature, float *pressure, float *altitude) {

    // 步骤1:向控制寄存器写入 0x25,触发一次强制测量
    // 0x25 = 0b00100101
    //   osrs_t = 001 → 温度过采样 x1(采1次样)
    //   osrs_p = 001 → 气压过采样 x1(采1次样)
    //   mode   = 01  → Forced 模式(触发单次测量)
    ESP_ERROR_CHECK(bmp280_write_reg(BMP280_REG_CTRL_MEAS, 0x25));

    // 步骤2:等待测量完成
    // 状态寄存器 0xF3 的 bit3(measuring 位)= 1 表示正在测量
    // 循环读取状态,直到 bit3 变为 0(测量完成)或超时
    uint8_t status;
    int timeout = 100; // 最多等待 100 × 10ms = 1秒
    do {
        vTaskDelay(pdMS_TO_TICKS(10)); // 等待 10 毫秒再检查
        bmp280_read_reg(BMP280_REG_STATUS, &status, 1);
    } while ((status & 0x08) && --timeout); // 0x08 = bit3,检查 measuring 位
    if (timeout == 0) return ESP_ERR_TIMEOUT; // 超时则返回错误

    // 步骤3:突发读取 6 字节原始数据(从 0xF7 开始)
    // 手册要求必须一次性连续读取全部 6 字节,保证数据一致性
    // 数据布局:[气压高8位][气压中8位][气压低4位+4位填充]
    //           [温度高8位][温度中8位][温度低4位+4位填充]
    uint8_t data[6];
    ESP_ERROR_CHECK(bmp280_read_reg(BMP280_REG_PRESS_MSB, data, 6));

    // 步骤4:将 3 字节拼接成 20 位 ADC 原始值
    // 气压:data[0]是高8位,data[1]是中8位,data[2]高4位是低4位
    int32_t adc_P = ((int32_t)data[0] << 12) | ((int32_t)data[1] << 4) | (data[2] >> 4);
    // 温度:data[3]是高8位,data[4]是中8位,data[5]高4位是低4位
    int32_t adc_T = ((int32_t)data[3] << 12) | ((int32_t)data[4] << 4) | (data[5] >> 4);

    // 步骤5:用校准参数进行补偿计算,得到真实物理值
    // 注意:必须先算温度(更新 t_fine),再算气压!
    *temperature = bmp280_compensate_T_int32(adc_T) / 100.0f; // 单位转换:0.01°C → °C
    *pressure    = bmp280_compensate_P_int64(adc_P) / 256.0f; // 单位转换:1/256 Pa → Pa
    *altitude    = pressure_to_altitude(*pressure);            // 由气压推算海拔

    return ESP_OK;
}

/* =============================================
   主函数 app_main()
   ESP-IDF 程序的入口,相当于 Arduino 的 setup() + loop()
   ============================================= */
void app_main(void) {
    ESP_LOGI(TAG, "BMP280 强制模式驱动启动");

    // ---- 第1步:初始化 I2C 总线 ----
    // 配置 I2C 总线参数(引脚、速率等)
    i2c_master_bus_config_t bus_cfg = {
        .clk_source = I2C_CLK_SRC_DEFAULT,       // 使用默认时钟源
        .i2c_port = I2C_PORT,                     // 使用 I2C 控制器 0
        .scl_io_num = I2C_MASTER_SCL_IO,          // SCL 引脚
        .sda_io_num = I2C_MASTER_SDA_IO,          // SDA 引脚
        .glitch_ignore_cnt = 7,                   // 毛刺过滤(忽略小于7个时钟周期的干扰)
        .flags.enable_internal_pullup = true,     // 启用内部上拉电阻
    };
    ESP_ERROR_CHECK(i2c_new_master_bus(&bus_cfg, &bus_handle)); // 创建 I2C 总线

    // 在总线上注册 BMP280 设备
    i2c_device_config_t dev_cfg = {
        .dev_addr_length = I2C_ADDR_BIT_LEN_7,   // 7位 I2C 地址
        .device_address = BMP280_SENSOR_ADDR,     // BMP280 地址 0x76
        .scl_speed_hz = I2C_MASTER_FREQ_HZ,       // 通信速率 400kHz
    };
    ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle)); // 添加设备

    // ---- 第2步:验证芯片 ID ----
    // 读取 0xD0 寄存器,BMP280 应返回 0x58
    // 这一步确认连接的确实是 BMP280,而不是其他传感器
    uint8_t chip_id;
    ESP_ERROR_CHECK(bmp280_read_reg(BMP280_REG_CHIP_ID, &chip_id, 1));
    if (chip_id != 0x58) {
        ESP_LOGE(TAG, "BMP280 ID错误: 0x%02X", chip_id); // 打印错误并停止
        vTaskDelete(NULL);
    }
    ESP_LOGI(TAG, "BMP280 ID验证通过");

    // ---- 第3步:软复位 ----
    // 向复位寄存器写入 0xB6,让传感器恢复出厂默认状态
    // 复位后:Sleep 模式,过采样关闭,滤波器关闭
    bmp280_write_reg(BMP280_REG_RESET, 0xB6);
    vTaskDelay(pdMS_TO_TICKS(10)); // 等待 10ms 让复位完成

    // ---- 第4步:读取出厂校准参数 ----
    // 从 0x88 开始读取 24 字节,包含温度和气压的校准系数
    // 每个参数由 2 字节(低字节在前)拼成 16 位整数
    uint8_t calib[24];
    ESP_ERROR_CHECK(bmp280_read_reg(BMP280_REG_CALIB_START, calib, 24));
    dig_T1 = (uint16_t)(calib[1] << 8 | calib[0]); // 温度校准参数 T1
    dig_T2 = (int16_t) (calib[3] << 8 | calib[2]); // 温度校准参数 T2
    dig_T3 = (int16_t) (calib[5] << 8 | calib[4]); // 温度校准参数 T3
    dig_P1 = (uint16_t)(calib[7] << 8 | calib[6]); // 气压校准参数 P1
    dig_P2 = (int16_t) (calib[9] << 8 | calib[8]); // 气压校准参数 P2
    // ... P3 到 P9 同理,依次从 calib 数组中读取
    dig_P3 = (int16_t)(calib[11] << 8 | calib[10]);
    dig_P4 = (int16_t)(calib[13] << 8 | calib[12]);
    dig_P5 = (int16_t)(calib[15] << 8 | calib[14]);
    dig_P6 = (int16_t)(calib[17] << 8 | calib[16]);
    dig_P7 = (int16_t)(calib[19] << 8 | calib[18]);
    dig_P8 = (int16_t)(calib[21] << 8 | calib[20]);
    dig_P9 = (int16_t)(calib[23] << 8 | calib[22]);
    ESP_LOGI(TAG, "校准参数读取完成");

    // ---- 第5步:配置滤波器 ----
    // 向配置寄存器(0xF5)写入 0x00
    // 0x00 表示:IIR 滤波器关闭(Filter::Off),待机时间 0.5ms
    // 注意:根据 BMP280 规格,CONFIG 寄存器的写入必须在 Sleep 模式下进行,
    //       软复位后传感器默认处于 Sleep 模式,所以这里可以直接写入
    bmp280_write_reg(BMP280_REG_CONFIG, 0x00);

    // ---- 第6步:循环触发 5 次单次测量 ----
    // 每次调用 bmp280_force_measurement() 触发一次 Forced 模式测量:
    //   1. 写控制寄存器 → 传感器开始采样
    //   2. 等待采样完成
    //   3. 读取 6 字节原始数据
    //   4. 用校准参数换算成真实温度、气压、海拔
    float temp, press, altitude;
    for (int i = 0; i < 5; i++) {
        if (bmp280_force_measurement(&temp, &press, &altitude) == ESP_OK) {
            // press 单位是 Pa,除以 100 转换为 hPa(百帕,气象常用单位)
            // 例如:101325 Pa ÷ 100 = 1013.25 hPa(标准大气压)
            ESP_LOGI(TAG, "温度: %.2f °C | 气压: %.2f hPa | 海拔: %.2f m",
                     temp, press / 100.0f, altitude);
        }
        vTaskDelay(pdMS_TO_TICKS(2000)); // 每次测量间隔 2 秒
    }

    ESP_LOGI(TAG, "测量完成");
    // 程序结束,app_main 返回后 ESP-IDF 会自动删除此任务
}

觉醒,然后燎原。 © 2026 门主引擎